﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Smallpointer.UnitTest.Framework;

namespace Smallpointer.UnitTest.Base
{
    public partial class MainWindow : Form
    {
        private TextWriterTraceListener DebugListener;
        private readonly StringBuilder DebugLines = new StringBuilder();
        private StringWriter DebugWriter;

        private readonly StringBuilder ConsoleLines = new StringBuilder();
        private StringWriter ConsoleWriter;

        private readonly StringBuilder ResultLines = new StringBuilder();
        private StringWriter ResultWriter;

        private ISynchronizeInvoke Invoker;
        private Timer Ticker;
        public MainWindow()
        {
            InitializeComponent();
            InitLiseners();
            InitInvokeView();
        }

        private void InitLiseners()
        {
            DebugListener = new TextWriterTraceListener();
            Debug.Listeners.Add(DebugListener);
            DebugWriter = new StringWriter(DebugLines);
            DebugListener.Writer = DebugWriter;
            ConsoleWriter = new StringWriter(ConsoleLines);
           
            

            ResultWriter = new StringWriter(ResultLines);
            Invoker = this;
            Ticker = new Timer
            {
                Interval = 100,
            };
            Ticker.Tick += (Ticker_Tick);
            Ticker.Start();
        }

        void Ticker_Tick(object sender, EventArgs e)
        {
            flush();
        }

        void flush()
        {
            if (exResultBox.Text != DebugLines.ToString())
                exResultBox.Text = DebugLines.ToString();
            if (topResultBox.Text != ResultLines.ToString())
                topResultBox.Text = ResultLines.ToString();
            if (outBox.Text != ConsoleLines.ToString())
                outBox.Text = ConsoleLines.ToString();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        void InitInvokeView()
        {
            var validateType = GetAssemblyType();
            foreach (var type in validateType)
            {
                var top = InvokeView.Nodes.Add(string.Empty, type.Name);
                var methods = type.GetMethods();
                foreach (var method in methods)
                {
                    var testMethods = method.GetCustomAttributes(typeof(TestMethod), true);
                    if (testMethods.Length > 0)
                    {
                        var item = top.Nodes.Add(method.Name);
                        item.ImageKey = type.Name;
                        item.Name = method.Name;
                    }
                }
            }
            InvokeView.NodeMouseDoubleClick += (NodeMouseDoubleClick);
        }

        private void NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Parent == null)
            {
                return;
            }
            var typename = e.Node.ImageKey;
            var methodname = e.Node.Name;
            if (string.IsNullOrEmpty(typename) || string.IsNullOrEmpty(methodname))
            {
                Debug.WriteLine("Can not find the mehod.");
                return;
            }
            ExecuteMethod(typename, methodname);
        }

        static List<Type> GetAssemblyType()
        {
            var assembly = Assembly.GetExecutingAssembly();
            var types = assembly.GetTypes();
            var validateType = new List<Type>();
            foreach (var type in types)
            {
                var testClasses = type.GetCustomAttributes(typeof(TestClass), true);
                if (testClasses.Length > 0)
                {
                    validateType.Add(type);
                }
            }
            return validateType;
        }
        void ExecuteMethod(string typename, string methodname)
        {
            var type = GetAssemblyType(typename);
            var method = type.GetMethod(methodname);
            Console.SetOut(ConsoleWriter);
            try
            {
                ResultWriter.WriteLine("Begin running :" + method.Name + " ....");
                method.Invoke(Activator.CreateInstance(type), null);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                if (ex.InnerException != null)
                {
                    Debug.WriteLine(ex.InnerException.Message);
                    Debug.WriteLine(ex.InnerException.StackTrace);
                }
                Debug.WriteLine(string.Format("[{0}]", DateTime.Now) + method.Name + " throw exceptions \r\n");
            }
            finally
            {
                ResultWriter.WriteLine("Running :" + method.Name + " Done.");
            }
        }

        static Type GetAssemblyType(string name)
        {
            var validateType = GetAssemblyType();
            Type t = null;
            foreach (var type in validateType)
            {
                if (type.Name != name) continue;
                t = type;
                break;
            }
            return t;
        }
    }
}